package com.budayi.common.config;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;


@Aspect
@Configuration
public class TransactionConfiguration {
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com..service..*.*(..))";

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {

        DefaultTransactionAttribute PROPAGATION_REQUIRED = new DefaultTransactionAttribute();
        PROPAGATION_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute PROPAGATION_SUPPORTS = new DefaultTransactionAttribute();
        PROPAGATION_SUPPORTS.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);


        DefaultTransactionAttribute PROPAGATION_REQUIRED_READONLY = new DefaultTransactionAttribute();
        PROPAGATION_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        PROPAGATION_REQUIRED_READONLY.setReadOnly(true);

        DefaultTransactionAttribute PROPAGATION_REQUIRES_NEW = new DefaultTransactionAttribute();
        PROPAGATION_REQUIRES_NEW.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);


        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        //读操作
        source.addTransactionalMethod("query*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("find*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("get*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("load*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("count*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("list*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("check*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("qry*", PROPAGATION_SUPPORTS);
        source.addTransactionalMethod("select*", PROPAGATION_SUPPORTS);

        //写操作
        source.addTransactionalMethod("save*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("del*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("add*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("upd*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("insert*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("creat*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("edit*", PROPAGATION_REQUIRED);
        source.addTransactionalMethod("remove*", PROPAGATION_REQUIRED);

        //挂起新事物，不回滚总事务提交
        source.addTransactionalMethod("*Client*", PROPAGATION_REQUIRES_NEW);
        source.addTransactionalMethod("*", PROPAGATION_SUPPORTS);

        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}